/*******************************************************************************
 *
 *    Copyright (c) Dolphin Browser
 *
 *    ViewTest
 *
 *    ScrollPageView
 *    TODO File description or class description.
 *
 *    @author: derron
 *    @since:  2010-3-8
 *    @version: 1.0
 *
 ******************************************************************************/
package com.sdk.widget.threescreen.scrollview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * ScrollPageView of ViewTest.
 *
 * @author derron
 *
 */
public class ScrollablePageView extends FrameLayout {

    private int curPageNumber;

    private int firstShownPageNumber;

    private View.OnFocusChangeListener focusChangeListener;

    private boolean isPageFirstShown;

    private FlingableLinearLayout pageContainer;

    private PageEventObserver pageEventObserver;

    private PageProvider pageProvider;

    private List<PageView> pages;

    private FlingableLinearLayout.OnScrollListener scrollListener;


    public ScrollablePageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public ScrollablePageView(Context context) {
        super(context);
        init(context);
    }

    public ScrollablePageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context){
        pages = new ArrayList<PageView>();
        isPageFirstShown = true;
        pageContainer = new FlingableLinearLayout(context);
        pageContainer.setHorizontalScrollBarEnabled(true);
        pageContainer.setVerticalScrollBarEnabled(false);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.FILL_PARENT,
                FrameLayout.LayoutParams.FILL_PARENT);
        addView(pageContainer, params);

        focusChangeListener = new View.OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if(hasFocus){
                    int n = ((PageView)v).getPageNumber();
                    showPage(n);
                }
            }

        };
    }

    private void fingToPage(int index) {
        curPageNumber = index;
        int width = getMeasuredWidth();
        width *= index;
        pageContainer.flingTo(width);
    }

    private int getLeftPageNum(int x) {
        int width = getMeasuredWidth();
        return (x - 1) / width;
    }

    private int getRightPageNum(int x) {
        int width = getMeasuredWidth();

        int n = x / width + 1;

        int size = pages.size();

        if (n >= size) {
            n = -1;
        }
        return n;
    }

    private void preparePage(int paramInt) {
//		int j = paramInt - 1;
//		int k = paramInt + 1;
//		if (j >= 0 && pages.get(j).getChildCount() == 0) {
//			pageProvider.requestPage(pages.get(j));
//			removePage(k + 1);
//		}
//		int size = this.pages.size();
//		if (k < size && pages.get(k).getChildCount() == 0) {
//			pageProvider.requestPage(pages.get(k));
//			removePage(j - 1);
//		}
        requestLayout();
    }

    private void removePage(int index) {
        if (index >= 0 && index < pages.size()) {
            pages.get(index).removeAllViews();
        }
    }

    private void scrollToPage(int x) {
        int width = getMeasuredWidth();
        int j = (width / 2 + x) / width;
        showPage(j, true);
    }

    private void showPage(int index, boolean paramBoolean) {
        if(index < 0 || index > pages.size() - 1){
            return;
        }
        curPageNumber = index;
        int count = pages.get(index).getChildCount();
        if (0 == count) {
            pageProvider.requestPage(pages.get(index));
        }
        int measureWidth = getMeasuredWidth();
        if (0 != measureWidth) {
            if (paramBoolean) {
                measureWidth *= index;
                pageContainer.flingTo(measureWidth);
            } else {
                measureWidth *= index;
                pageContainer
                        .scrollTo(measureWidth, pageContainer.getScrollY());
            }
        } else {
            firstShownPageNumber = index;
        }

        if (isPageFirstShown && 0 == index) {
            isPageFirstShown = false;
            if (null != scrollListener) {
                FlingableLinearLayout pc = pageContainer;
                int scrollX = pc.getScrollX();
                int scrollY = pc.getScrollY();
                scrollListener.onScrollChanged(scrollX, scrollY,
                        scrollX, scrollY);
            }
        }
    }

    public PageView getPage(int index) {
        return pages.get(index);
    }

    @Override
    protected void onFinishInflate() {
        pageContainer.setAlwaysDrawnWithCacheEnabled(true);
        pageContainer.setAnimationCacheEnabled(true);
        scrollListener = new FlingableLinearLayout.OnScrollListener() {

            @Override
            public void onScrollChanged(int paramInt1, int paramInt2,
                    int paramInt3, int paramInt4) {
                //TODO ...
                int width = getMeasuredWidth();
                if(0 == width){
                    preparePage(0);
                    if( null != pageEventObserver){
                        pageEventObserver.onPageShown(pages.get(0));
                    }
                }
                else {
                    int i = paramInt1 % width;
                    if(0 == i){
                        int index = paramInt1 / width;
                        int size = pages.size();
                        if(index >= size){
                            if(size > 0){
                                index = size - 1;
                            }
                            else {
                                return;
                            }
                        }
                        preparePage(index);
                        if( null != pageEventObserver){
                            pageEventObserver.onPageShown(pages.get(index));
                        }
                    }
                }
            }

        };
        pageContainer.setOnScrollListener(scrollListener);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        if (MotionEvent.ACTION_UP == action) {
            int scrollX = pageContainer.getScrollX();
            FlingableLinearLayout.FlingDirection direction = pageContainer.getFlingDirection();
            if (FlingableLinearLayout.FlingDirection.NONE == direction) {
                scrollToPage(scrollX);
            } else if (FlingableLinearLayout.FlingDirection.LEFT == direction) {
                int n = getRightPageNum(scrollX);
                if (n >= 0) {
                    fingToPage(n);
                }
            } else {
                int n = getLeftPageNum(scrollX);
                if (n >= 0) {
                    fingToPage(n);
                }
            }
        }
        return false;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        pageContainer.layout(0, 0, r - l, b - t);
        if (isPageFirstShown) {
            isPageFirstShown = false;
            int i = firstShownPageNumber;
            int j = getMeasuredWidth();
            int k = i * j;
            int scrollY = pageContainer.getScrollY();
            pageContainer.scrollTo(k, scrollY);
        }
        if (changed) {
            showPage(curPageNumber);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int mode = MeasureSpec.getMode(widthMeasureSpec);
        if (MeasureSpec.EXACTLY == mode) {
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            Iterator<PageView> iterator = pages.iterator();
            while (iterator.hasNext()) {
                PageView pageView = iterator.next();
                pageView.setPageDimension(width, height);
            }
            int size = pages.size();
            width *= size;
            int widthSpec = MeasureSpec.makeMeasureSpec(width,
                    MeasureSpec.EXACTLY);
            pageContainer.measure(widthSpec, heightMeasureSpec);
        }

        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    public void setPageEventObserver(PageEventObserver observer) {
        pageEventObserver = observer;
    }

    public void setPageProvider(PageProvider provider) {
        pageProvider = provider;
    }

    public void setTotalPages(int n) {

        int i = 0;
        Context context = getContext();
        while(pageContainer.getChildCount() > 0){
            ViewGroup view = (ViewGroup) pageContainer.getChildAt(0);
            view.removeAllViews();
            pageContainer.removeView(view);
        }
        pages.clear();
        while (i < n) {
//			PageView pageView = (PageView) inflater.inflate(R.layout.page_frame, null);
            PageView pageView = new PageView(context);
            pageView.setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
            pageView.setPageNumber(i);
            pageView.setOnFocusChangeListener(focusChangeListener);
            pageContainer.addView(pageView);
            pages.add(pageView);
            i++;
        }
    }

    public int getTotalPages(){
        return pages.size();
    }

    public void showPage(int i) {
        showPage(i, false);
    }

    public static interface PageEventObserver {
        public void onPageShown(PageView paramPageView);
    }

    public static interface PageProvider {
        public boolean requestPage(PageView paramPageView);
    }

}
